package com.ch8.demo01;


import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

/**
 * @author woldier
 * @version 1.0
 * @description 线程池
 * @date 2023/5/16 18:18
 **/
@Slf4j(topic = "c.Thread")
public class ThreadPool {

    /**
     * 阻塞队列
     */
    private final BlockingQueue<Runnable> queue;

    /**
     * 工作线程
     */
    private final HashSet<Worker> workers = new HashSet<>();

    /**
     * 核心数目
     */

    private int coreSize;
    /**
     * 超时时间
     */
    private final long timeOut;

    /**
     * 时间单位
     */
    private final TimeUnit timeUnit;


    private final RejectPolicy<Runnable> rejectPolicy;
    public ThreadPool(int coreSize, long timeOut, TimeUnit timeUnit, int capacity,RejectPolicy<Runnable> rejectPolicy) {
        this.coreSize = coreSize;
        this.timeOut = timeOut;
        this.timeUnit = timeUnit;
        this.queue = new BlockingQueue<>(capacity);
        this.rejectPolicy = rejectPolicy;
    }


    public void execute(Runnable runnable) {
        synchronized (workers) {
            if (workers.size() < coreSize) {
                //如果当前的线程池中又空余线程,则新建一个worker,将其放入线程池中,并开启该工作线程
                Worker worker = new Worker(runnable);
                log.debug("当前worker数量少于coreSize,新增worker,{}", worker);
                workers.add(worker);
                worker.start();
            } else {
                log.debug("当前worker数量已经达到最大,进入阻塞队列,{}", runnable);
                //如果当前线程池中没有多余空闲线程,那么则将其放入阻塞队列中,让已有的工作线程进行调用
                //queue.put(runnable);  //队满死等
                //boolean offer = queue.offer(runnable, timeOut, timeUnit); //队满有超时时间的等
                /*拒绝策略*/
                queue.tryPut(runnable,rejectPolicy);
            }
        }
    }

    class Worker extends Thread {
        private Runnable runnable;

        public Worker(Runnable runnable) {
            this.runnable = runnable;
        }

        @Override
        public void run() {
            //while (runnable != null || (runnable = queue.take()) != null) { // 刚开启本worker之后,runnable != null 为真,因此不会走后面的逻辑,当本次执行玩之后,runnable设置为null,则会进入第二个判断逻辑,从阻塞队列中获取
            while (runnable != null || (runnable = queue.poll(timeOut,timeUnit)) != null) {
                try {
                    runnable.run();
                } catch (Exception e) {
                    throw new RuntimeException("执行任务出错");
                } finally {
                    runnable = null;
                }
            }
            //阻塞队列中返回元素为null则会退出,此时需要从线程池中将当前worker移除
            synchronized (workers) {
                log.debug("当前阻塞队列返回了null,说明为空,worker结束");
                workers.remove(this);
            }
        }
    }
}
